//
// Created by Key-Box-Min on 28/05/2020.
//

#ifndef UNTITLED_CONTAINER_H
#define UNTITLED_CONTAINER_H


#include <iostream>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <cstdlib>
#include <cstring>
//#include <unordered_set>
//#include <hash_map>
using namespace std;

class Utils{
public:
    template<typename T>
    size_t hash(const T &  key) {
        static std::hash<T> hashf;
        return hashf(key);
    }
};

template<typename T,typename U = Utils>
class Array{
public:
    Array(int _len):len(_len){data = new T[len];}
    ~Array(){delete data;}

    T & operator[](const int & index){return data[index];}

    T* data;
    int len;
    U utils;
};

template<typename T,typename U = Utils>
class SetArray{
public:
    SetArray(int _len):len(_len){
        keys = new T[len];
        memset(keys,-1,len*sizeof(T));
        nexts = new int[len];
        memset(nexts,-1,len*sizeof(int));
    }
    ~SetArray(){
        delete[] keys;
        delete[] nexts;
    }

    void insert(const T & key) {
        int index = findEmplyIndex(key);
        if(index < 0 || keys[index] == key)return;
        memcpy(keys+index,&key,sizeof(key));
    }

    T & operator[](const int & index){return keys[index];}

    const bool & content(const T & key){
        return (findIndex(key) != -1);
    }

    int findIndex(const T& key){
        int index = findIndexCore(key);
        if(keys[index] != key)return -1;
        return index;
    }

    //    int findEmplyIndex(const T& key){
//        int index = hash(key);
//        if(index >= len)index %= len;
//        int indexold = index;
//        std::cout<<index<<"-- \t ";
//        while ((*(int *) &keys[index]) != 0 && keys[index] != key){
//            index+=1;
//            if(index < 0) index = -index;
//            if(index >= len)index %= len;
//            if(indexold == index)return -1;
//            std::cout<<index<<"-- \t ";
//        }
////        std::cout<<index<<"===";
//        return index;
//    }

    int findEmplyIndex(const T& key){return __findEmplyIndex(findIndexCore(key),key);}
    int findIndexCore(const T& key){return __findIndexCore(hash(key),key);}

protected:
    virtual int __findEmplyIndex(int index,const T& key){
        int indexold = index;

        while ((*(int *) &keys[index]) != -1 && keys[index] != key) {
            index++;
            if (index < 0) index = -index;
            if (index >= len)index %= len;
            if (indexold == index)return -1;
            std::cout << index << "-- \t ";
        }

        if(indexold != index){
            nexts[indexold] = index;
        }

        return index;
    }

    virtual int __findIndexCore(int index,const T& key){
        if(index >= len)index %= len;

        while(nexts[index] != -1 && (*(int *) &keys[index]) != -1 && keys[index] != key){
            index = nexts[index];
            std::cout << index << ">> \t ";
        }

        return index;
    }

    virtual int hash(const T& key){
        int index = utils.hash(key);
        if(index < 0) index = -index;
        return index;
    }

public:
    T* keys;
    int* nexts;
    int len;
    U utils;
};

template<typename K,typename V,typename U = Utils>
class MapArray : public SetArray<K,U>{
public:
    MapArray(int _len)
            :SetArray<K,U>(_len){
        vals = new V[this->len];
        memset(vals,'\0',this->len*sizeof(V));
    }
    ~MapArray(){
        delete[] vals;
    }

    void insert(const K & key,const V & val) {
        const int & index = findEmplyIndex(key);
        if(index < 0 || this->keys[index] == key)return;
        memcpy(this->keys+index,&key,sizeof(key));
        memcpy(vals+index,&val,sizeof(val));
    }

    V & operator[](const K & key){return vals[findIndex(key)];}
    V & operator[](const K && key){return vals[findIndex(key)];}

    V * vals;
};

template<class V,class U = Utils>
using SetArrayPtr = SetArray<V,U>*;

template<class K,class V,class U = Utils>
using MapArrayPtr = MapArray<K,V>*;

template<class V,class U = Utils>
using ArrayPtr = Array<V,U>*;

template<class V,class U = Utils>
ArrayPtr<V,U> createArray(const vector<V> & _set){
    auto rul = new Array<V,U>(_set.size());
    int index = 0;
    for(auto item=_set.begin();item != _set.end();item++)
        rul->data[index++] = *item;
    return rul;
}

template<class V,class U = Utils>
SetArrayPtr<V,U> createSet(const set<V> & _set){
    auto rul = new SetArray<V,U>(_set.size());
    for(auto item=_set.begin();item != _set.end();item++)
        rul->insert(*item);
    return rul;
}

template<class K,class V,class U = Utils>
MapArrayPtr<K,V,U> createMap(const map<K,V> &_map){
    auto rul = new MapArray<K,V,U>(_map.size());
    for(auto item=_map.begin();item != _map.end();item++)
        rul->insert(item->first,item->second);
    return rul;
}


#endif //UNTITLED_CONTAINER_H
